﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Threading;
using System.Windows.Forms;

using Interface.Logging;

using TracedReality.Logging;
using TracedReality.RayTracing;

namespace Interface.UI
{
    public partial class RenderForm : Form
    {
        private Thread worker = null;
        private bool rendering = false;
        private Scene scene = null;

        public RenderForm()
        {
            InitializeComponent();
        }

        private void RenderForm_Load(object sender, EventArgs e)
        {
            this.Icon = Icon.FromHandle(Properties.Resources.test.GetHicon());
            setStatus("");

            VisualLog vl = new VisualLog();
            Log.addReceiver(vl);
            vl.Show();
            vl.Left = this.Right;
            vl.Top = this.Top;
            vl.Height = 250;
            vl.Width = 500;

            /*try
            {
                Stream str = File.OpenRead("trololol.file");
                BinaryFormatter des = new BinaryFormatter();
                setImage((Bitmap)des.Deserialize(str));
                str.Close();
            }
            catch (Exception ex) { Console.WriteLine(ex); }*/

            //Scene s = Scene.makeLotsOfGeometryScene(1, 0.2);
            //File.AppendAllText("1k_spheres.yaml", s.ToString());
        }

        private void tsbSettings_Click(object sender, EventArgs e)
        {
            if (!rendering)
            {
                SettingsForm sf = new SettingsForm();
                if (sf.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    if (scene != null) { RayTracer.giveScene(scene); }
                    setStatus("Settings saved");
                }
            }
        }

        private void tsbOpen_Click(object sender, EventArgs e)
        {
            if (!rendering)
            {
                if (ofdOpen.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    scene = Scene.loadSceneFromFile(ofdOpen.FileName);

                    if (scene == null) { return; }

                    Visualization.Visualizer vis = new Visualization.Visualizer(ref scene);
                    vis.Show();

                    RayTracer.giveScene(scene);

                    Log.log("Scene opened: " + ofdOpen.FileName);
                    Log.log("Primitives: " + scene.shapes.Count);
                    Log.log("Lights: " + scene.lights.Count);
                    setStatus("Scene opened");
                    setEnabled(tsToolStrip, tsbRender, true);
                }
            }
        }

        private void tsbSave_Click(object sender, EventArgs e)
        {
            if (sfdSave.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                pbImage.Image.Save(sfdSave.FileName);
                Log.log("Image saved: " + sfdSave.FileName);
                setStatus("Image saved");
            }
        }

        private void tsbRender_Click(object sender, EventArgs e)
        {
            if (!rendering)
            {
                tProgressChecker.Enabled = true;
                setVisible(tsToolStrip, tspbProgress, true);
                worker = new Thread(doRender);
                worker.Start();
            }
        }

        private void doRender()
        {
            Stopwatch st = new Stopwatch();

            setStatus("Rendering image");
            rendering = true;

            st.Start();
            Bitmap img = RayTracer.traceImage();
            st.Stop();

            tProgressChecker.Enabled = false;
            setProgress(1);
            setVisible(tsToolStrip, tspbProgress, false);

            /*try
            {
                Stream str = File.Create("trololol.file");
                BinaryFormatter ser = new BinaryFormatter();
                ser.Serialize(str, img);
                str.Close();
            }
            catch (Exception ex) { }*/

            setImage(img);

            Log.log("Render completed in " + st.Elapsed);
            setStatus("Render complete");
            rendering = false;

            setEnabled(tsToolStrip, tsbSave, true);
        }

        private delegate void SetStatusCallBack(string s);
        private void setStatus(string s)
        {
            if (tsToolStrip.InvokeRequired)
            {
                SetStatusCallBack stcb = new SetStatusCallBack(setStatus);
                this.Invoke(stcb, new object[] { s });
            }
            else
            {
                tslStatus.Text = s;
            }
        }

        delegate void SetEnabledCallBack(ToolStrip ts, ToolStripItem tsi, bool b);
        private void setEnabled(ToolStrip ts, ToolStripItem tsi, bool b)
        {
            if (ts.InvokeRequired)
            {
                SetEnabledCallBack secb = new SetEnabledCallBack(setEnabled);
                this.Invoke(secb, new object[] { ts, tsi, b });
            }
            else
            {
                tsi.Enabled = b;
            }
        }

        delegate void SetVisibleCallBack(ToolStrip ts, ToolStripItem tsi, bool b);
        private void setVisible(ToolStrip ts, ToolStripItem tsi, bool b)
        {
            if (ts.InvokeRequired)
            {
                SetVisibleCallBack svcb = new SetVisibleCallBack(setVisible);
                this.Invoke(svcb, new object[] { ts, tsi, b });
            }
            else
            {
                tsi.Visible = b;
            }
        }

        private delegate void SetImageCallBack(Image i);
        private void setImage(Image i)
        {
            if (pbImage.InvokeRequired)
            {
                SetImageCallBack sicb = new SetImageCallBack(setImage);
                this.Invoke(sicb, new object[] { i });
            }
            else
            {
                pbImage.Image = i;
                pbImage.Size = i.Size;
            }
        }

        private delegate void SetProgressCallBack(double p);
        private void setProgress(double p)
        {
            if (tsToolStrip.InvokeRequired)
            {
                SetProgressCallBack spcb = new SetProgressCallBack(setProgress);
                this.Invoke(spcb, new object[] { p });
            }
            else
            {
                tspbProgress.Value = (int)(100 * p);
            }
        }

        private void tProgressChecker_Tick(object sender, EventArgs e)
        {
            setProgress(RayTracer.getProgress());
        }
    }
}
